#include "clib_tcp_fsm.h"
#include "clib_sock.h"
#include "clib_stack.h"
#include "clib_tuple_hash.h"
#include "clib_tcp_misc.h"
#include "clib_stack_trace.h"
#include "clib_stack_conf.h"

#define socket_list_add_timeout(ctx,sock,ts) 	\
	do { 										\
		if((ctx)->time_out > 0) {				\
			if(!(sock)->on_timeout_list) {		\
				clib_queue_insert_tail(&(ctx)->timeout_list,&(sock)->timeout_list); \
				(sock)->on_timeout_list = true;										\
			} else {																\
				clib_queue_del(&(sock)->timeout_list);								\
				clib_queue_insert_tail(&(ctx)->timeout_list,&(sock)->timeout_list); \
				(sock)->on_timeout_list = true;									 	\
			}																	 	\
			(sock)->cur_time = (ts);											 	\
		}																		 	\
	} while(0)

static inline void 
tcp_state_listen(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts, 
		clib_sock_t* sock,tcp_hdr_t* tcph) {
	/** TCP 监听被动打开连接处理 **/
	if (tcph->th_flags == TH_SYN) {
		if (sock->tcp_stream.tcp_state == TCP_ST_LISTEN) {
			/** SYN ACK 变化 **/
			sock->tcp_stream.rcv_nxt = (tcph->seq + 1);
		}
		sock->tcp_stream.tcp_state = TCP_ST_SYN_RCVD;
		sock->tcp_stream.irs = tcph->seq;
		tcp_send_pack(ctx, netif, sock, TH_SYN|TH_ACK, send_data_flag);
	} else {
		clib_stack_trace("tcp_state_listen flag not match\n");
	}
}

static inline void 
tcp_state_syn_sent(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts, clib_sock_t* sock, const ip4_hdr_t* iph,tcp_hdr_t* tcph, i32_t data_len)
{
	/** 处理接受 SYN/ACK 数据包 **/
	tcp_stream_t *stream = &sock->tcp_stream;

	if(tcph->th_flags != (TH_SYN | TH_ACK)) {
		clib_stack_trace("tcp_state_syn_sent flag not match\n");
		/** TODO rst 相关处理 **/
		return ;
	}

	/** TODO 测试 **/
	if(tcph->ack) {
		if(tcph->th_ack != (stream->iss + 1)) {
			clib_stack_trace("tcp_state_syn_sent flag not match\n");
			return ;
		}
		stream->irs     = tcph->th_seq;
		stream->snd_nxt = tcph->th_ack;
		stream->snd_una = stream->snd_nxt;
		stream->snd_wnd = tcph->window;
		stream->snd_max_wnd = tcph->window;
		stream->rcv_nxt = tcph->th_seq + 1;
	}

	if(TCP_CMP_SEQ(stream->snd_una,stream->iss) > 0) {
		stream->snd_wl1 = tcph->th_seq;
		stream->snd_wl2 = tcph->th_ack;
	}

	if(stack_cfg.hand_ack) {
		tcp_send_pack(ctx, netif, sock, TH_ACK, send_data_flag);
	}

	stream->tcp_state = TCP_ST_ESTABLISHED;

	/** 添加到epoll事件队列 **/
	if(sock->ep && sock->ev.events & CLIB_EPOLLOUT) {
		if(!sock->on_ep_list) {
			if(stack_cfg.lock) {
				clib_spinlock_lock(&((clib_epoll_t*)sock->ep)->lock);
			}
			clib_queue_insert_tail(&((clib_epoll_t*)sock->ep)->event_list,&sock->ep_list);
			if(stack_cfg.lock) {
				clib_spinlock_unlock(&((clib_epoll_t*)sock->ep)->lock);
			}
			sock->on_ep_list = true;
			sock->ep->event_post++;

		}
	}

	socket_list_add_timeout(ctx,sock,cur_ts);
}

static inline void 
tcp_state_syn_recv(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,
		clib_sock_t* sock,tcp_hdr_t* tcph)
{
	/** TODO 处理接收 三次握手最后 ACK 数据包 **/
	clib_sock_t *listen;
	u32_t prior_cwnd;
	tcp_stream_t* stream = &sock->tcp_stream;
	int ret;
	if (tcph->ack) {
		/* check if ACK of SYN */
		if (tcph->th_ack != stream->iss + 1) {
			clib_stack_trace("tcp_state_syn_recv ack not match\n");
			return;
		}
		stream->irs = tcph->seq;
		stream->snd_una = tcph->ack;
		stream->snd_nxt = tcph->ack;
		stream->rcv_nxt = stream->irs + 1;

		stream->tcp_state = TCP_ST_ESTABLISHED;

		listen = clib_tuple_hash_table_search(ctx->listen_table,&tcph->dest, 1);
		if(listen) {
			clib_queue_insert_tail(&listen->tcp_listen.accept,&sock->list);
			sock->on_acpt_list = true;
			listen->tcp_listen.accept_n++;
		} else {
			clib_stack_trace("tcp_state_syn_recv  error not reason\n");
			return ;
		}

		/** TODO 计算 RTT **/

		if(listen->ep) {
			if(listen->ev.events & CLIB_EPOLLIN) {
				if(!listen->on_ep_list) {
					clib_queue_insert_tail(&((clib_epoll_t*)listen->ep)->event_list,&listen->ep_list);
					((clib_epoll_t*)listen->ep)->event_post++;
					listen->on_ep_list = true;
				}
			}
		}

		socket_list_add_timeout(ctx, sock, cur_ts);
	} else {
		/** TODO 是从新加入，还是 重新发送 syn/ack **/
		// TRACE_DBG("Stream %d (TCP_ST_SYN_RCVD): No ACK.\n", 
		// 		cur_stream->id);
		// /* retransmit SYN/ACK */
		// cur_stream->snd_nxt = sndvar->iss;
		// AddtoControlList(mtcp, cur_stream, cur_ts);
	}
}


static inline void
tcp_state_estab(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,
		clib_sock_t* sock, tcp_hdr_t* tcph,
		uint8_t *payload, int payloadlen) 
{
	tcp_stream_t* stream = &sock->tcp_stream;
	if (tcph->syn) {
		/** TODO socket 畸形syn 标记异常 **/
		clib_stack_trace("tcp_state_estab flag not match\n");
		return ;
	}

	if(tcp_check_seq(ctx, sock, tcph, payloadlen) < 0) {
		/** TODO 错误处理 **/
		return ;
	}

	if (payloadlen > 0) {
		clib_tcp_buffer_recv_put_data(stream->recv_buffer, tcph->th_seq, payload, payloadlen);
		if(stream->recv_buffer->ready_len > 0) {
			/** TODO 加入到epoll队列 在刚加入到epoll 是主动轮询socket一次 **/
			if(sock->ep && sock->ev.events & CLIB_EPOLLIN) {
				if(!sock->on_ep_list) {
					clib_queue_insert_tail(&((clib_epoll_t*)sock->ep)->event_list,&sock->ep_list);
					((clib_epoll_t*)sock->ep)->event_post++;
					sock->on_ep_list = true;
				}
			}
		}
	}
	
	if (tcph->ack) {
		tcp_check_ack(ctx, sock, tcph,payloadlen);
		clib_tcp_buffer_send_ack_data(stream->send_buffer,tcph->th_ack);
	}

	if (tcph->fin) {
		/** TODO 结束处理 注意状态变化 **/
		// /* process the FIN only if the sequence is valid */
		// /* FIN packet is allowed to push payload (should we check for PSH flag)? */
		// if (seq + payloadlen == cur_stream->rcv_nxt) {
		// 	cur_stream->state = TCP_ST_CLOSE_WAIT;
		// 	TRACE_STATE("Stream %d: TCP_ST_CLOSE_WAIT\n", cur_stream->id);
		// 	cur_stream->rcv_nxt++;
		// 	AddtoControlList(mtcp, cur_stream, cur_ts);

		// 	/* notify FIN to application */
		// 	RaiseReadEvent(mtcp, cur_stream);
		// } else {
		// 	EnqueueACK(mtcp, cur_stream, cur_ts, ACK_OPT_NOW);
		// 	return;
		// }
	}
}

static inline void 
tcp_state_close_wait(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts, clib_sock_t* sock, tcp_hdr_t* tcph) 
{
	if(clib_tcp_check_seq(ctx,sock,0, tcph->th_seq) == rn_error) {
		return ;
	}

	if(tcph->rst) {
		sock->tcp_stream.tcp_state = TCP_ST_CLOSED;
		return ;
	}
	/** TODO 清楚所有所在的链表 **/
	clib_queue_insert_tail(&ctx->free_list,&sock->list);
	/** TODO 添加到关闭链表 **/
}

static inline void
tcp_state_fin_wait1(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,clib_sock_t* sock, tcp_hdr_t* tcph) 
{
	tcp_stream_t* stream = &sock->tcp_stream;

	if(CNET_TCP_CMP_SEQ(stream->snd_nxt,tcph->th_ack) == 0) {

	}

	if(CNET_TCP_CMP_SEQ(stream->rcv_nxt,tcph->th_seq) == 0) {

	}

	if(tcph->ack) {
		stream->tcp_state = TCP_ST_FIN_WAIT2;
	}
	if(tcph->fin) {
		stream->rcv_nxt++;
		/** TODO  fin 允许带载荷 **/
		stream->tcp_state = TCP_ST_CLOSING;
	}
}

static inline void
tcp_state_fin_wait2(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,clib_sock_t* sock, tcp_hdr_t* tcph) 
{
	tcp_stream_t* stream = &sock->tcp_stream;

	if(CNET_TCP_CMP_SEQ(stream->snd_nxt,tcph->seq) == 0) {

	}
	
	if(CNET_TCP_CMP_SEQ(stream->snd_nxt,tcph->ack) == 0) {

	}

	/** TODO **/
	if(tcph->fin) {
		/** 发送最后的 ack **/
		stream->tcp_state = TCP_ST_TIME_WAIT;
	}
	return ;
}

static inline void
tcp_state_closing(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,clib_sock_t* sock, 
		tcp_hdr_t* tcph) 
{
	clib_tcp_stream_t* stream = &sock->tcp_stream;

	if(CNET_TCP_CMP_SEQ(stream->snd_nxt, tcph->ack) == 0) {

	}

	if(CNET_TCP_CMP_SEQ(stream->rcv_nxt, tcph->seq) == 0) {

	}

	if(tcph->ack) {
		stream->tcp_state = TCP_ST_TIME_WAIT;
		/** TODO 加入到time wiat **/
	}
}

static inline void
tcp_state_timewait(stack_ctx_t *ctx, stack_netif_t *netif, u32_t cur_ts,clib_sock_t* sock, 
		struct tcphdr* tcph)
{
	clib_tcp_stream_t* stream = &sock->tcp_stream;

	if(tcph->fin) {
		//stream->tcp_state = TCP_ST_TIME_WAIT;
		/** TODO 加入到time wiat **/
	}
}

i32_t 
clib_tcp_process_ipv4_packet(stack_ctx_t* ctx, stack_netif_t* netif,ip4_hdr_t* ipv4,i32_t ip_len,u64_t cur_ts) 
{
	tcp_stream_t      *stream;
    clib_sock_t       *sock;
    tcp_hdr_t *tcph   = (tcp_hdr_t*) ((u08_t*)ipv4 + (ipv4->ihl << 2));
    u08_t *payload    = (u08_t *)tcph + (tcph->doff << 2);
    i32_t payload_len = ip_len - (payload - (u08_t *)ipv4);
	tcp_hdr_t segment = *tcph;

	segment.th_seq = ntohl(tcph->th_seq);
	segment.th_ack = ntohl(tcph->th_ack);
	segment.th_win = ntohs(tcph->th_win);
	segment.th_sport = ntohs(tcph->th_sport);
	segment.th_dport = ntohs(tcph->th_dport);
	
    tuple_t      tuple;
    tuple.ipv4_tuple.l_addr = ipv4->daddr;
    tuple.ipv4_tuple.r_addr = ipv4->saddr;
    tuple.ipv4_tuple.r_port = tcph->th_sport;
    tuple.ipv4_tuple.l_port = tcph->th_dport;
    tuple.ipv4_tuple.procotol = 0x06;

    /** TODO 查找socket **/
	sock = clib_tuple_hash_table_search(ctx->hash_table,&tuple.ipv4_tuple,1);
    if(!sock) {
		if(!(tcph->th_flags == TH_SYN)) {
			return rn_error;
		}
        sock = clib_get_sock_new_by_stack(ctx);
		sock->ipv4 = 1;
		stream = &sock->tcp_stream;
    	sock_init(sock, socket_type_sock_tcp, 1, &tuple);
		stream->irs = segment.th_seq;
		stream->rcv_nxt = segment.th_seq;
        clib_tuple_hash_table_insert(ctx->hash_table,&tuple);
    }

	sock->cur_time = cur_ts;
    stream = &sock->tcp_stream;
    /** TODO rset **/
    if(stream->tcp_state > TCP_ST_SYN_RCVD) {
		if(tcp_check_seq(ctx, sock, &segment, payload_len)) {
			clib_stack_trace("tcp check seq error (%s:%d)\n",__FILE__,__LINE__);
			return rn_error;
		}
    }

    switch (stream->tcp_state) 
	{
	case TCP_ST_LISTEN:
		tcp_state_listen(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_SYN_SENT:
		tcp_state_syn_sent(ctx, netif, cur_ts, sock, ipv4, tcph, payload_len);
		break;

	case TCP_ST_SYN_RCVD:
		tcp_state_syn_recv(ctx, netif, cur_ts, sock, tcph);
		// /** syn/ack 丢包的情况 **/
		// if(tcph->th_flags == TH_SYN && seq == sock->tcp_stream.irs) {
		// 	clib_tcp_st_listen(ctx,cur_ts,sock,tcph);
		// } else {
		// 	clib_tcp_st_syn_recv(ctx, cur_ts, sock, tcph, seq, ack_seq);
		// 	if(payload_len > 0 && stream->tcp_state == TCP_ST_ESTABLISHED) {
		// 		clib_tcp_st_established(ctx, cur_ts, sock, tcph, seq, ack_seq, payload, payload_len, window);
		// 	}
		// }
		break;

	case TCP_ST_ESTABLISHED:
		tcp_state_estab(ctx, netif, cur_ts, sock, tcph, payload, payload_len);
		break;

	case TCP_ST_CLOSE_WAIT:
		tcp_state_close_wait(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_LAST_ACK:
		// Handle_TCP_ST_LAST_ACK(mtcp, cur_ts, iph, ip_len, cur_stream, tcph, 
		// 		seq, ack_seq, payloadlen, window);
		break;
	
	case TCP_ST_FIN_WAIT1:
		tcp_state_fin_wait1(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_FIN_WAIT2:
		tcp_state_fin_wait2(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_CLOSING:
		tcp_state_closing(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_TIME_WAIT:
		tcp_state_timewait(ctx, netif, cur_ts, sock, tcph);
		break;

	case TCP_ST_CLOSED:
		break;

	}
    return rn_ok;
}

i32_t 
clib_tcp_process_ipv6_packet(stack_ctx_t* ctx, stack_netif_t* netif,ip6_hdr_t* ipv6,i32_t ip_len,u64_t cur_ts)
{
    return rn_ok;
}
